package actions.productos;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.xwork.StringUtils;

import services.movimiento.MovimientoStockService;
import services.producto.ProductoService;
import util.GSonHelper;
import util.SearchOperator;
import actions.base.BaseAction;

import com.google.gson.Gson;

import config.Constants;
import dto.LineaRemitoDTO;
import dto.MovimientoStockDTO;
import dto.ProductoDTO;
import dto.RemitoDTO;
import dto.SearchDTO;
import dto.StockDTO;
import exceptions.CannotDeleteException;
import exceptions.CannotImportException;
import exceptions.CannotSaveException;

public class ProductoAction extends BaseAction {
	
	private static final long serialVersionUID = 1L;

	private ProductoService productoService;
	
	private MovimientoStockService movimientoStockService;
	
	private ProductoDTO productoDTO;
	
	private List<StockDTO> stockDTO;
	
	private RemitoDTO remitoDTO;
	
	private String importacion;
	
	private String query;
	
	@Override
	public String execute() {
		return SUCCESS;
	}
	
	/**
	 * Agrega un nuevo producto
	 * @return
	 */
	public String agregar() {
		
		// TODO hacer validaciones
		
		try {
			productoService.save(productoDTO);
		} catch (CannotSaveException e) {
			setOk("false");
			setMensaje("No se ha podido almacenar el producto");
			return SUCCESS_AGREGAR;
		}
		setOk("true");
		setMensaje("El producto se ha almacenado correctamente");
		return SUCCESS_AGREGAR;
	}
	
	
	private ProductoDTO toDTO(String[] values) throws CannotImportException {
		
		String codigo 		= StringUtils.trim(values[0]);
		String descripcion 	= StringUtils.trim(values[1]);
		String marca 		= StringUtils.trim(values[2]);
		String medida 		= StringUtils.trim(values[3]);
		String modelo 		= StringUtils.trim(values[4]);
		String precioB2B 	= StringUtils.trim(values[5]);
		String precioLista 	= StringUtils.trim(values[6]);
		String proveedor	= StringUtils.trim(values[7]);
		
		ProductoDTO productoDTO = new ProductoDTO();
		productoDTO.setCodigo(codigo);
		productoDTO.setDescripcion(descripcion);
		productoDTO.setMarca(marca);
		productoDTO.setMedida(medida);
		productoDTO.setModelo(modelo);
		
		try {
			if (precioB2B != null && !"".equals(precioB2B)) {
				productoDTO.setPrecioB2B(Double.parseDouble(precioB2B));
			}
			if (precioLista != null && !"".equals(precioLista)) {
				productoDTO.setPrecioLista(Double.parseDouble(precioLista));
			}
		} catch (NumberFormatException nfe) {
			throw new CannotImportException();
		}
		productoDTO.setProveedor(proveedor);
		return productoDTO;
	}
	
	/**
	 * Importa masivamente productos
	 * Los productos llegan en el parametro importacion, de la siguiente manera: 
	 * codigo;descripcion;marca;medida;modelo;precioB2B;precioLista;precioOferta;proveedor;tipo\n
	 */
	public String importar() {
		
		String no_importados = "";
		String log_file_content = "";
		Integer importados = new Integer("0");
		
		// Obtiene los productos
		String[] productos = importacion.split("\n");
		for (int i = 0; i < productos.length; i++) {
			
			// Obtiene los valores del producto
			String producto = productos[i];
			String[] values = producto.split(";");
			String codigo 	= StringUtils.trim(values[0]);
			try {
				// Convierte a DTO
				ProductoDTO productoDTO = toDTO(values);
				
				// Se fija si es una actualizacion o un producto nuevo
				SearchDTO searchDTO = new SearchDTO();
				searchDTO.addCriteria("codigo", codigo, SearchOperator.EQUAL);
				List<ProductoDTO> p = productoService.search(searchDTO);
				if (p != null && p.size() > 0) {
					
					// UPDATE
					System.out.println("IMPORTACION: update producto con codigo" + codigo);
					ProductoDTO productoInDB = p.get(0);
					productoDTO.setId(productoInDB.getId());
					productoService.merge(productoDTO);
					
					importados++;
				} else {
					
					// Agrega los almacenes
					List<StockDTO> stocks = new ArrayList<StockDTO>();
					stocks.add(new StockDTO(new Integer(0), Constants.ALMACEN_LUJAN));
					stocks.add(new StockDTO(new Integer(0), Constants.ALMACEN_RODRIGUEZ));
					productoDTO.setStocks(stocks);
					
					// Save
					System.out.println("IMPORTACION: insert producto con codigo" + codigo);
					productoService.save(productoDTO);
					
					importados++;
				}
				System.out.println("IMPORTACION: Producto con codigo: " + codigo + " importado correctamente");
				
			} catch (Exception e) {
				
				// Linea de producto para escribir en archivo de log
				log_file_content += producto + "\n";
				// Codigo para mostrar mensaje de error
				no_importados += codigo + ",";
			}
		}
		
		// Generacion error log file
		String log_filename = config.Constants.PRODUCTO_IMPORT_LOG_PATH + "product_import_" + new Date().getTime() + ".log";
		try {
			if (log_file_content.length() > 0) {
				PrintWriter out = new PrintWriter(log_filename);
				out.print(log_file_content);
				out.close();
			}
		} catch (FileNotFoundException e) {
			System.out.println("No se pudo generar archivo de log para importacion de producto");
		}

		String mensaje = "Se han importado: " + importados + " productos correctamente. <br/><br/>";
		if (log_file_content.length() > 0 ) {
			mensaje += "Problemas con: " + no_importados + " <br/> Se ha generado el archivo <b>" + log_filename + "</b> con los registros que han tenido problema";
		}
		setOk("true");
		setMensaje(mensaje);
		return SUCCESS_AGREGAR;
	}
	
	
	/**
	 * Borra un producto
	 * @return
	 */
	public String borrar() {
		
		// TODO hacer validacion sobre ID
		
		try {
			productoService.delete(id);
		} catch (CannotDeleteException e) {
			setOk("false");
			setMensaje("El producto no se ha podido eliminar");
			return SUCCESS_AGREGAR;
		}
		setOk("true");
		setMensaje("El producto se ha eliminado correctamente");
		return SUCCESS_AGREGAR;
	}

	/**
	 * Obtiene una lista de todos los productos
	 * @return	la lista
	 */
	public String getProductos() {

		List<ProductoDTO> productos = productoService.findAll();
		
		Gson gson = GSonHelper.getInstance();
		String productosStr = gson.toJson(productos);
		
		setLista(productosStr);
		return SUCCESS_LISTADO;
	}
	
	/**
	 * Obtiene un producto
	 * @return el producto
	 */
	public String getProducto() {
		
		// TODO validacion sobre ID
		
		ProductoDTO producto = productoService.findById(id);
		
		Gson gson = GSonHelper.getInstance();
		String productoStr = gson.toJson(producto);
		setLista(productoStr);
		return SUCCESS_JSON;
	}
	
	
	/**
	 * Agrega una recepcion de mercaderia
	 * @return
	 */
	public String recepcion() {
		
		// Remito values
		String numero  = remitoDTO.getNumero();
		String almacen = remitoDTO.getAlmacen();

		// Lineas remito
		List<LineaRemitoDTO> lineasRemito = remitoDTO.getLineasRemito();
		for (LineaRemitoDTO lineaRemitoDTO : lineasRemito) {
			
			if (lineaRemitoDTO == null) { continue; }
			
			// Valores linea
			String idProducto = lineaRemitoDTO.getIdProducto();
			Integer cantidad  = (lineaRemitoDTO.getCantidad() == null) ? 0 : lineaRemitoDTO.getCantidad();
			
			// Obtiene el producto en cuestion
			ProductoDTO productoDTO = productoService.findById(idProducto);
			
			// Obtiene los stocks del producto
			List<StockDTO> stocks = productoDTO.getStocks();

			// Actualiza los stocks
			for (StockDTO stockDTO : stocks) {
				
				String almacenStock = stockDTO.getAlmacen();
				if (almacenStock.equalsIgnoreCase(almacen)) {
				
					Integer cantidadStock = (stockDTO.getCantidad() == null) ? 0 : stockDTO.getCantidad();
					stockDTO.setCantidad(cantidadStock + cantidad);
				}
			}
			
			// Update del producto
			try {
				productoService.merge(productoDTO);
				
				// Se genera un movimiento de stock por recepcion de mercaderia
				MovimientoStockDTO movimientoStockDTO = new MovimientoStockDTO();
				movimientoStockDTO.setFecha(new Date());
				movimientoStockDTO.setCantidad(cantidad);
				movimientoStockDTO.setRemito(numero);
				movimientoStockDTO.setProductoDTO(productoDTO);
				movimientoStockService.merge(movimientoStockDTO);
			} catch (CannotSaveException e) {
				setOk("false");
				setMensaje("No se ha podido almacenar el remito");
				return SUCCESS_AGREGAR;
			}
		}
		
		setOk("true");
		setMensaje("La recepción de mercadería se ha almacenado correctamente");
		return SUCCESS_AGREGAR;
	}
	
	
	/**
	 * Obtiene una lista de productos para mostrar en un listado 'typeahead'
	 * @return	la lista json
	 */
	public String getProductoList() {
		
		SearchDTO searchDTO = new SearchDTO();
		searchDTO.addCriteria("codigo_marca_modelo_descripcion", getQuery(), SearchOperator.OR_LIKE);
		
		List<ProductoDTO> productos = productoService.search(searchDTO);
		
		Gson gson = GSonHelper.getInstance();
		String productosStr = gson.toJson(productos);
		
		setLista(productosStr);
		return SUCCESS_LISTADO;
	}

	/**
	 * Obtiene todos los productos
	 * @return	la lista json
	 */
	public String getAllProductos() {
		
		List<ProductoDTO> productos = productoService.findAll();
		
		Gson gson = GSonHelper.getInstance();
		String productosStr = gson.toJson(productos);
		
		setLista(productosStr);
		return SUCCESS_LISTADO;
	}
	
	
	/**
	 * Busca productos
	 */
	public String buscar() {
		
		// TODO validacion sobre DTO
		
		SearchDTO searchDTO = new SearchDTO();
		searchDTO.addCriteria("codigo", productoDTO.getCodigo(), SearchOperator.START);
		searchDTO.addCriteria("marca", productoDTO.getMarca(), SearchOperator.LIKE);
		searchDTO.addCriteria("descripcion", productoDTO.getDescripcion(), SearchOperator.LIKE);
		searchDTO.addCriteria("proveedor", productoDTO.getProveedor(), SearchOperator.LIKE);
		
		List<ProductoDTO> productos = productoService.search(searchDTO);
		
		Gson gson = GSonHelper.getInstance();
		String productosStr = gson.toJson(productos);
		
		setLista(productosStr);
		return SUCCESS_LISTADO;
	}
	
	/**
	 * Getters & Setters
	 */
	public ProductoDTO getProductoDTO() {
		return productoDTO;
	}

	public List<StockDTO> getStockDTO() {
		return stockDTO;
	}

	public void setStockDTO(List<StockDTO> stockDTO) {
		this.stockDTO = stockDTO;
	}

	public String getQuery() {
		return query;
	}

	public void setQuery(String query) {
		this.query = query;
	}
	
	public RemitoDTO getRemitoDTO() {
		return remitoDTO;
	}

	public void setRemitoDTO(RemitoDTO remitoDTO) {
		this.remitoDTO = remitoDTO;
	}

	public String getImportacion() {
		return importacion;
	}

	public void setImportacion(String importacion) {
		this.importacion = importacion;
	}

	public void setProductoDTO(ProductoDTO productoDTO) {
		this.productoDTO = productoDTO;
	}

	public ProductoService getProductoService() {
		return productoService;
	}

	public void setProductoService(ProductoService productoService) {
		this.productoService = productoService;
	}

	public MovimientoStockService getMovimientoStockService() {
		return movimientoStockService;
	}

	public void setMovimientoStockService(
			MovimientoStockService movimientoStockService) {
		this.movimientoStockService = movimientoStockService;
	}
	
}
